var mwg = null; // the MindWave Graph JIT object (SpaceTree or whatever)
var isStateInit = true; // TODO for now
/** 
 * CONSTANTS
 */
var KEY_GRAPH = 'mwg',
KEY_TEST = 'TESTY',
K_ST_INIT = 'state init load',
K_NUM_ACTIVE = 'num active viewers';

var SEP = '_';
 
var NEWROOT = '.r_',
 ADDCHILD = '.c_',
 LEN_CMD = 3;

/** 
 * Initialization
 */
function init() {
	conlog("MindWave Startup.");
	conlog("STARTUP STATE: ");
	printState(); // getViewer may be null due to participants add comes later
	conlog("Initializing graph and registering state update handler.");	
	initializeGraph();
	initializeStateHandling();
}

// TODO deinit not in use
function deinit() {
	conlog("MindWave Shutdown.");
	if (wave.getState()) {
		var numActive = wave.getState().get(K_NUM_ACTIVE);	
		//submitUpdate(K_ST_INIT, null, "CLEAR STATE INIT FLAG FOR NOW"); // TODO IMPORTANT
		// TODO finish deinit
		//conlog("Removing flag signalling the initial state load.");
		//submitUpdate(K_ST_INIT, null); // TODO IMPORTANT only do this for last participant using this gadget
		//conlog("Saving special graph state info.");
		//saveGraph();
	}
}

function initializeStateHandling() {
	if (wave && wave.isInWaveContainer()) {
		wave.setStateCallback(stateUpdated);
	}
}

function initializeGraph() {
	var graphdiv = document.getElementById('graph');
	var w = 600, h = 300; // TODO div.offsetwidth?
	var canvas = new Canvas('mycanvas', {
		'injectInto': 'graph',
		'width': w,
		'height': h,
		'backgroundColor': '#000000'
	});

	var graphConfig = {
		orientation: "top",
		duration: 400,         //set duration for the animation
		transition: Trans.Quart.easeInOut,         //set animation transition type
		levelDistance: 30, //50,         //set distance between node and its children
		Node: {
			height: 25,
			width: 120,
			type: 'rectangle',
			color: '#ccc',
			overridable: true
		},
		Edge: {
			type: 'bezier',
			overridable: true,
			lineWidth: 4
		},
		onCreateLabel: function(label, node){  
         label.id = node.id;              
         label.innerHTML = node.name;  
         label.onclick = newNodeForm; // function () {labelClick(this)};
         //set label styles  
         var style = label.style;  
         style.width = 120 + 'px';         
         style.cursor = 'pointer';  
         style.color = '#000';  
         style.fontSize = '0.8em';  
         style.textAlign= 'center';
         style.fontFamily = "Arial";
         style.padding = "3px";
     }
	};

	mwg = new ST(canvas, graphConfig);
}

/**
 * Input form popup
 */

function newNodeForm(event){
	var nid = event.target.id;
	var formContainer = document.createElement('div');
	formContainer.setAttribute('id','newNodeForm');
	var form = "<form name='newNode' method='post' action='' id='newNode'><input type='text' name='newNodeName' id='newNodeName' value='' /><input type='hidden' name='nodeID' id='nodeID' value='"+nid+"' />&nbsp;<input type='button' value='Submit' onclick='submitNewNode(); return false;' /></form>";
	// var form = "<input type='text' value='' id='newNodeName' name='newNodeName' />&nbsp;<div id='nodeSubmitButton' onclick='>Submit</div>";
	formContainer.innerHTML = form;
	var bodyEl = document.getElementsByTagName('body')[0];
	bodyEl.appendChild(formContainer);
	// TODO: Need to get coordinates and place form over node that has been clicked.
}
/**
 * This function passes the form data in the form of a JS Object called "newNodeData".
 */

function submitNewNode() {
	var newNodeForm = document.getElementById("newNode");
	var newNodeData = new Object();
	newNodeData['parentID'] = newNodeForm.nodeID.value;
	newNodeData['newNodeName'] = newNodeForm.newNodeName.value;
	var formContainer = document.getElementById("newNodeForm");
	var bodyEl = document.getElementsByTagName('body')[0];
	bodyEl.removeChild(formContainer);
	//alert('Parent ID: '+newNodeData['parentID']+' New node text: '+newNodeData['newNodeName']);
	addChildDelta(newNodeData['newNodeName'], newNodeData['parentID']);
}


/**
 * Loads GRAPH into display.
 * mwg must have already been initialized.
 * 
 * GRAPH - an object with JIT "JSON" tree (or graph) format
 */
function loadGraph(graph) {
	mwg.loadJSON(graph); // FYI JIT doesn't like empty graphs {} for some functions so save graph should not save such
	mwg.compute();     //compute node positions and layout
	mwg.onClick(mwg.root);     //emulate a click on the root node // TODO any issue with empty graph?	
}

// TODO possible to save graph only just before gadget unload? window unload might lose access to state first?
// FIXME LATER deinit on unload may be causing trouble during gadget deletion
function saveGraph() {
	if (mwg && mwg.root && wave.getState()) { // REQUIRES 1) graph with root 2) root must not be false in logical context
		var gstring = gadgets.json.stringify(mwg.json);
		conlog("***** DELTA: Saving graph. Graph: " + gstring);
		submitUpdate(KEY_GRAPH, gstring);
	} else if (wave.getState()) {
		conlog("***** DELTA: There is no graph to save. Clearing previous saved graph (if exists).");
		submitUpdate(KEY_GRAPH, null); // ensures clear memory of any initial graph
	} else {
		conlog("No gadget state available and no graph to save.");
	}
	return true;
}

/**
 * Event and delta management
 */
function submitUpdate(key, value, msg) {
	if (msg) {
		conlog("***** DELTA: " + msg);
	}
	var d = {};
	d[key] = value;
	wave.getState().submitDelta(d);
}

function stateUpdated() {
	conlog("State callback triggered ***********");
	printState();
	conlog("***** DELTA: Removing test item (if exists): " + KEY_TEST);
	submitUpdate(KEY_TEST, null);

	var state = wave.getState();
	
	//isStateInit = true; // TODO for testing
	// load graph from previous state if this is first person to open the gadget
	if (false) { // TODO disabled for testing if (isStateInit && state.get(KEY_GRAPH)) {
		var gstring = state.get(KEY_GRAPH);
		var graph = gadgets.json.parse(gstring);
		conlog("Loading graph: " + ostring(graph) + " from JSON: " + gstring);
		loadGraph(graph);
		submitUpdate(K_ST_INIT, 'done', "Note that state has been init by someone.");
	} else if (isStateInit) {
		conlog("NEW GADGET. There is no previous graph.");
		conlog("Test using canned tree ******************") // TODO testing
		loadGraph(testTree);
		isStateInit = false;
		//submitUpdate(K_ST_INIT, 'done', "Note that state has been init by someone.");
	} else {
		conlog("Someone opened gadget recently. Skipping load from previous save.");
	}
	
	// TODO add child and save graph, add root node and save, etc
	var keys = state.getKeys();
	for (var i=0; i<keys.length; i++) { // TODO make cmd queue instead?
		var key = keys[i];
		var cmd = key.substring(0, LEN_CMD);
		var data = state.get(key);
		switch (cmd) {
			case ADDCHILD:
				conlog("TODO REALLY ADD CHILD: " + data);
				var dataJson = gadgets.json.parse(data);
				var parent = mwg.graph.getNode(dataJson.pn);
				//conlog("got parent? " + parent.name);
				var n = gadgets.json.parse(dataJson.n);
				var node = new Graph.Node(n);
				//parent.addAdjacency(node, {});
				//st.onClick(parent.id); // TODO necessary?
				alert(n.data.vname + " wants to add '"+ n.name + "' below '" + parent.name + "'");
				//saveGraph();
				submitUpdate(key, null, "Done adding child. Remove command."); // Remove cmd
				break;
		}
	}
}

function labelClick(thisLabel) {
	var parentId = thisLabel.id;
	conlog("Label clicked. Node Id: " + parentId); // TODO work with jeff
	// event.target is like <div id="a" class="node" style="padding: 3px; position: absolute; width: 150px; cursor: pointer; color: rgb(0, 0, 0); font-size: 0.8em; text-align: center; font-family: Arial; left: 325px; top: 270px;">
	newNodeForm(thisLabel);
}

function addChildButtonClick(parentId) {
	addChildDelta('Test BUTTON click on ' + parentId, parentId);
}

/**
 * Graph data management
 */
function addChildDelta(text, parentId) {
	conlog("*********** GRAPHCHANGING EVENT: ADDING CHILD ***********");
	var msg = makeNodeMessage(text, parentId);
	conlog("TODO Adding child to parent: " + msg);
	var key = ADDCHILD + msg.nid;
	submitUpdate(key, gadgets.json.stringify(msg));
}

function makeNodeMessage(text, parentId) {
	var msg = {'pn': parentId, 'n': "", 'nid': ""};
	var n = {};
	var data = {};
	if (wave.getViewer()) {
		var p = wave.getViewer();
		//data.vid = p.getId();
		data.vname = p.getDisplayName();
		//data.vimg = getThumbnailUrl(); // TODO put this in later
	} else {
		data.vname = "(Missing Viewer)";
	}
	msg.nid = n.id = 'n_' + data.vname + new Date().getTime(); // TODO uniq id
	n.name = text; // node name is the label text
	n.children = [];

	n.data = data;
	msg.n = gadgets.json.stringify(n); // TODO ok for now.
	return msg;
}

/**
 * 
 */

gadgets.util.registerOnLoadHandler(init); //window.addEventListener("load", init, false);
//window.addEventListener("unload", deinit, true); // usecapture==true to get in early

/***************
 * DEBUGGING AND UTILITY
 * TODO remove some of this debugging and utility stuff
 *
 */
 
var debug = false;

function conlog(msg) {
	if (debug) {
		console.log(msg);
	}
}

function printState() {
	if (debug) {
		console.log("GADGET ENV AND STATE -------------------------");
		if (wave.getViewer()) {
			console.log("  Viewer: " + wave.getViewer().getDisplayName() + " ID:" + wave.getViewer().getId());
		} else {
			console.log("Viewer load is incomplete. (You're not a participant yet!)");
		}
		if (wave.getState()) {
			console.log("  Gadget State: ");
			console.log("  " + wave.getState().toString());	
		} else {
			console.log("  There is no Gadget State.");
		}
	}
}

function ostring(a) { // FEH what's the one-liner for this?
	var s = "";
	for (var x in a) {
	    s += x + ": " + a[x] + ", ";
	}
	return s;
}

 /// DEBUG: Quickies
function onclickTestDelta() {
	conlog("TEST DELTA BUTTON CLICKED.");
	conlog("Submitting test delta...");
	submitUpdate(KEY_TEST, 'testy');
	conlog("...Delta submitted.");
}

function onclickGetSetDelta() { // TODO remove this debugging callback
	conlog("testButtonClicked(): submitting a simple delta");
	var value = parseInt(wave.getState().get('count', '0'));
	wave.getState().submitDelta({
		'count': value + 1
		});
}

var testTree = {
	id: "a",
	name: "MindWave Project",
	data: {},
	children: [	{
		id: "b",
		name: "display",
		data: {},
		children: [
			{id: "pret",
			name: "make prettier",
			data: {},
			children: [
				{
				id: "pret-col",
				name: "colour",
				data: {},
				children: []
				},
				{
				id: "pret-3d",
				name: "3D",
				data: {},
				children: []
				},
			]},
			{id: "nod",
			name: "rich nodes",
			data: {},
			children: []
		},]
	},
	{
		id: "c",
		name: "logic",
		data: {},
		children: [	{
			id: "d",
			name: "add nodes",
			data: {},
			children: []
		},
		{
			id: "ed",
			name: "edit content",
			data: {},
			children: []
		}
		]
	}
	]
};
